﻿using System;
using System.Collections.Generic;
using EnterpriseFramework.DataAccess.Validation;
using System.Reflection;
using System.ComponentModel;
//using System.ComponentModel;

namespace EnterpriseFramework.DataAccess
{
    public delegate void CPropertyChangedEventHandler(object sender, CPropertyChangedEventArgs e, int index);

    public class BaseEntity
    {
        public BaseEntity() { }

        public event CPropertyChangedEventHandler PropertyChanged;

        private int rowIndex = -1;
        internal int RowIndex { get { return rowIndex; } set { rowIndex = value; } }

        #region - Validation -
        private NotValidRuleList _NotValidRuleList = new NotValidRuleList();

        /// <summary>
        /// Gets a collection of Not Valid rules.
        /// </summary>
        public NotValidRuleList BrokenRules
        {
            get { return _NotValidRuleList; }
        }

        /// <summary>
        /// Adds a validation rule to the broken rules list if it is broken.
        /// </summary>
        protected void AddRule(Rule rule)
        {
            _NotValidRuleList.AddRule(rule);
        }

        /// <summary>
        /// An overload of "AddRule".
        /// </summary>
        protected void AddRule(string name, string description, bool isValid)
        {
            _NotValidRuleList.AddRule(new Rule(name, description, isValid));
        }

        /// <summary>
        /// Adds a list of broken rules to the current broken rules.
        /// </summary>
        protected void AddRules(NotValidRuleList brokenRules)
        {
            foreach (Rule rule in brokenRules)
                _NotValidRuleList.AddRule(rule);
        }

        /// <summary>
        /// An object is valid if none of the validation rules have been broken.
        /// </summary>
        public virtual bool IsValid
        {
            get
            {
                CheckRules();
                return (_NotValidRuleList.Count == 0);
            }
        }

        /// <summary>
        /// Allows a subclass to add rules.
        /// </summary>
        /// <remarks>
        /// Add rules using "AddRule" method.
        /// Rules can also be added anywhere else in the class (i.e. the property setters).
        /// </remarks>
        protected virtual void CheckRules()
        {
        }

        #endregion

        /// <summary>
        /// Used to notify if property is change.
        /// </summary>
        /// <param name="info"></param>
        /// <param name="value"></param>
        protected void NotifyPropertyChanged(String propertyName, object value)
        {
            if (PropertyChanged != null)
            {
                var v1 = this.GetType().GetProperty(propertyName).GetValue(this, null);
                if (value.Equals(v1))
                    return;

                PropertyChanged(this, new CPropertyChangedEventArgs(propertyName, value), RowIndex);
            }
        }

        public override bool Equals(object obj)
        {
            if (this.RowIndex == ((BaseEntity)obj).RowIndex)
                return true;
            else
                return false;
        }

        //internal T HasChanges<T>()
        //{
        //    Type currentType = this.GetType();

        //    var target = currentType.GetConstructors()[0].Invoke(null);

        //    TableAttribute tableAttr = (TableAttribute)currentType.GetCustomAttributes(typeof(TableAttribute), false)[0];
        //    BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly;
        //    while (tableAttr != null)
        //    {
        //        foreach (MemberInfo m in currentType.GetMembers(flags))
        //        {
        //            if (m.IsDefined(typeof(ColumnAttribute), false))
        //            {
        //                ColumnAttribute columnAttr = (ColumnAttribute)m.GetCustomAttributes(typeof(ColumnAttribute), false)[0];
        //                if (!columnAttr.AutoIncrement)
        //                {
        //                    object newValue = null;
        //                    object oldValue = null;
        //                    bool IsProperty = false;
        //                    if (m is FieldInfo)
        //                    {
        //                        FieldInfo f = (FieldInfo)m;
        //                        newValue = f.GetValue(this);
        //                        oldValue = f.GetValue(m_OriginalVersion);
        //                    }
        //                    else if (m is PropertyInfo)
        //                    {
        //                        PropertyInfo p = (PropertyInfo)m;
        //                        newValue = p.GetValue(this, null);
        //                        oldValue = p.GetValue(m_OriginalVersion, null);
        //                        IsProperty = true;
        //                    }



        //                    // Compare this version to original version
        //                    if (newValue == null && oldValue == null)
        //                        continue;

        //                    if (newValue == null && oldValue != null)
        //                    {
        //                        if (IsProperty)
        //                        {
        //                            PropertyInfo p = m as PropertyInfo;
        //                            p.SetValue(target, newValue, null);
        //                        }
        //                        else
        //                        {
        //                            FieldInfo f = m as FieldInfo;
        //                            f.SetValue(target, newValue);
        //                        }
        //                    }


        //                    if (newValue != null && oldValue == null)
        //                        return true;

        //                    if (newValue.Equals(oldValue))
        //                        continue;
        //                    else
        //                        return true;
        //                }
        //            }
        //        }

        //        //if (tableAttr.Inherit)
        //        //{
        //        //    currentType = currentType.BaseType;
        //        //    tableAttr = (TableAttribute)currentType.GetCustomAttributes(typeof(TableAttribute), false)[0];
        //        //}
        //        //else
        //        //{
        //        //    break;
        //        //}
        //    }

        //    return false;
        //}
    }

    public class CPropertyChangedEventArgs : PropertyChangedEventArgs
    {
        public CPropertyChangedEventArgs(string propertyName) : base(propertyName) { }

        public CPropertyChangedEventArgs(string propertyName, object propertyValue)
            : this(propertyName)
        {
            PropertyValue = propertyValue;
        }

        public object PropertyValue { get; set; }
    }
}
